home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / kms20src.lha / KMSAM / kmsam.c < prev    next >
C/C++ Source or Header  |  1995-09-24  |  76KB  |  2,652 lines

  1. /*************************************************************************
  2.  *
  3.  *   Copyright (C) 1995 Thomas Schwarz
  4.  *                      <kmshq@ruatha.muc.de>
  5.  *                      <Schwarz.Thomas@fhm.de>
  6.  *
  7.  *   This program is free software; you can redistribute it and/or modify
  8.  *   it under the terms of the GNU General Public License as published by
  9.  *   the Free Software Foundation; either version 2 of the License, or
  10.  *   any later version.
  11.  *
  12.  *   This program is distributed in the hope that it will be useful,
  13.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *   GNU General Public License for more details.
  16.  *
  17.  *   You should have received a copy of the GNU General Public License
  18.  *   along with this program; if not, write to the Free Software
  19.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  *************************************************************************/
  22.  
  23. #include "KMSAM.h"
  24. #include <KMS/KMS_def.h>
  25.  
  26. /* Defines */
  27.  
  28. #define VERSION "1.27"
  29.  
  30. #define MID_ADD     1
  31. #define MID_REMOVE  2
  32. #define MID_UP      3
  33. #define MID_DOWN    4
  34. #define MID_SORT    5
  35. #define MID_EDIT    6
  36. #define MID_OK      7
  37. #define MID_ABOUT   8
  38. #define MID_DOUBLE  9
  39. #define MID_PARENT  10
  40. #define MID_CHILD   11
  41. #define MID_PATH    12
  42. #define MID_SELAREA 13
  43. #define MID_CUT     14
  44. #define MID_COPY    15
  45. #define MID_PASTE   16
  46.  
  47. #define EID_USE     20
  48. #define EID_CANCEL  21
  49. #define EID_SELAB   22
  50. #define EID_NAMEAB  23
  51. #define EID_CGTYPE  24
  52.  
  53. /* Escape Sequences */
  54.  
  55. #define eR "\033r"
  56. #define eC "\033c"
  57. #define eL "\033l"
  58.  
  59. #define eN "\033n"
  60. #define eB "\033b"
  61. #define eI "\033i"
  62.  
  63. #define ePB "\0332"
  64. #define ePW "\0338"
  65.  
  66. /* Prototypes */
  67.  
  68. int main(int, char **);
  69. LONG DisplayDir(struct AreaNode *, struct AreaNode *);
  70. BOOL ReadAreaList(VOID);
  71. BOOL WriteAreaList(VOID);
  72. BOOL InitAreaFile(VOID);
  73. struct AreaNode *AddAN(VOID);
  74. VOID DeleteAN(struct AreaNode *);
  75. BOOL ParseArgs(VOID);
  76. VOID Sense(APTR, STRPTR);
  77. VOID ReadAccBits(VOID);
  78. BOOL WriteAccBits(VOID);
  79. struct AreaNode *SetArea(UWORD);
  80. struct AreaNode *ResolvePath(STRPTR);
  81. STRPTR PathParse(STRPTR, STRPTR);
  82. struct AreaNode *SeekAreaName(struct AreaNode *, STRPTR);
  83. struct AreaNode *AreaSearch(STRPTR);
  84. LONG InsertArea(struct AreaNode *);
  85. VOID RemoveArea(struct AreaNode *);
  86. VOID CleanUpAreaList(VOID);
  87. struct KMSBase *GetKMSBase(VOID);
  88. VOID CreatePath(STRPTR);
  89. VOID UpdatePath(VOID);
  90. VOID Upper(STRPTR);
  91. VOID Error(STRPTR);
  92. VOID TakeASem(BOOL);
  93. VOID DropASem(VOID);
  94. VOID TakeMSem(BOOL);
  95. VOID DropMSem(VOID);
  96.  
  97. /* Hooks */
  98.  
  99. SAVEDS ASM LONG list_dspfunc(
  100.    REG(a0) struct Hook *hook,
  101.    REG(a2) char **array,
  102.    REG(a1) struct AreaNode *area)
  103.    {
  104.    if (area)
  105.       *array = area->AreaData.Name;
  106.    else
  107.       *array = NULL;
  108.    return 0;
  109.    }
  110.  
  111. static struct Hook list_dsphook = {
  112.    {NULL, NULL},
  113.    (VOID *)list_dspfunc,
  114.    NULL, NULL
  115.    };
  116.  
  117. SAVEDS ASM LONG list_cmpfunc(
  118.    REG(a0) struct Hook *hook,
  119.    REG(a1) struct AreaNode *area1,
  120.    REG(a2) struct AreaNode *area2)
  121.    {
  122.    if (area1 && area2)
  123.       return stricmp(area1->AreaData.Name, area2->AreaData.Name);
  124.    else
  125.       return 0;
  126.    }
  127.  
  128. static struct Hook list_cmphook = 
  129.    {
  130.    {NULL, NULL},
  131.    (VOID *)list_cmpfunc,
  132.    NULL, NULL
  133.    };
  134.  
  135. /* Vars */
  136.  
  137. static Object *App       ; /* Application object      */
  138. static Object *WI_Manager; /* Main Window object      */
  139. static Object *WI_Editor ; /* Editor Window object    */
  140. static Object *LV_Areas  ; /* Areas Listview object   */
  141. static Object *LV_AccBits; /* AccBits Listview object */
  142. static Object *BT_Parent ; /* Parent Button object    */
  143. static Object *BT_Child  ; /* Child Button object     */
  144. static Object *BT_Add    ; /* Add Button object       */
  145. static Object *BT_Remove ; /* Remove Button object    */
  146. static Object *BT_Up     ; /* Up Button object        */
  147. static Object *BT_Down   ; /* Down Button object      */
  148. static Object *BT_Sort   ; /* Sort Button object      */
  149. static Object *BT_Edit   ; /* Edit Button object      */
  150. static Object *BT_Cut    ; /* Cut Button object       */
  151. static Object *BT_Copy   ; /* Copy Button object      */
  152. static Object *BT_Paste  ; /* Paste Button object     */
  153.  
  154. static Object *BT_EUse    ; /* Edit-Use Button object    */
  155. static Object *BT_ECancel ; /* Edit-Cancel Button object */
  156.  
  157. /* String-Gadget objects */
  158.  
  159. static Object *ST_Name;
  160. static Object *ST_Info;
  161. static Object *ST_MBName;
  162. static Object *ST_FilePath;
  163. static Object *ST_AccBit;
  164. static Object *ST_QuoteStr;
  165. static Object *ST_PQuoteStr;
  166. static Object *ST_ResendStr;
  167. static Object *ST_ForwardStr;
  168. static Object *ST_OriginStr;
  169. static Object *ST_Path;
  170. static Object *ST_HoldNum;
  171. static Object *ST_HoldDays;
  172.  
  173. /* Slider objects */
  174.  
  175. static Object *SL_RLevel;
  176. static Object *SL_WLevel;
  177. static Object *SL_ELevel;
  178.  
  179. /* Cycle objects */
  180.  
  181. static Object *CY_ATypeRoot;
  182. static Object *CY_ATypePublic;
  183.  
  184. static const char *CYA_ATypeRoot[] =
  185.    {
  186.    "Mail",
  187.    NULL
  188.    };
  189.  
  190. static const char *CYA_ATypePublic[] =
  191.    {
  192.    "News",
  193.    "Binary",
  194.    NULL
  195.    };
  196.  
  197. /* CheckMark objects */
  198.  
  199. static Object *CH_Group;
  200. static Object *CH_ToName;
  201. static Object *CH_NoRe;
  202. static Object *CH_Pseudos;
  203.  
  204. /* Page object */
  205.  
  206. static Object *PG_AType;
  207.  
  208. /* Menü */
  209.  
  210. static const struct NewMenu MenuList[] =
  211.    {
  212.    {NM_TITLE, "Project",   0,   0,  0, 0},
  213.    {NM_ITEM,  "About...",  "?", 0,  0, (APTR)MID_ABOUT},
  214.    {NM_ITEM,  NM_BARLABEL, 0,   0,  0, 0},
  215.    {NM_ITEM,  "Quit",      "Q", 0,  0, (APTR)MID_OK},
  216.    {NM_END,   NULL,        0,   0,  0, 0}
  217.    };
  218.  
  219. /* Misc */
  220.  
  221. STRPTR Areaname = NULL;
  222. struct AreaNode *CurrentArea = NULL;
  223. struct AreaNode *CurrentMother = NULL;
  224. struct Library *UMSBase = NULL;
  225. UMSUserAccount SysUMSAccount = NULL;
  226.  
  227. ULONG SystemStartups;
  228. TEXT AccBitNames[32][LEN_ACCBITNAME+1];
  229.  
  230. TEXT PathString[LEN_KMSPATH+1];
  231.  
  232. struct Area AreaStore; /* Paste-Puffer */
  233.  
  234. struct KMSBase *KMSBase = NULL;
  235.  
  236. /* Hauptprogramm */
  237.  
  238. /// "main"
  239.  
  240. int main(int argc, char *argv[])
  241.    {
  242.    struct AreaNode *an, *an2, *an3;
  243.    struct Area area;
  244.    BOOL running = TRUE, addflag = FALSE;
  245.    BOOL areaschanged = FALSE, bitschanged = FALSE;
  246.    BOOL cut = FALSE, error = FALSE;
  247.    ULONG signal, acc;
  248.    LONG num, entries, state, index;
  249.    UWORD idmerk;
  250.  
  251.    AreaStore.ID = 0;
  252.  
  253.    App = NULL;
  254.  
  255.    init();
  256.  
  257.    if (!ParseArgs())
  258.       Sense(App, NULL);
  259.  
  260.    if (!GetKMSBase())
  261.       Sense(App, NULL);
  262.  
  263.    App = ApplicationObject,
  264.       MUIA_Application_Title      , "KMS Area Manager",
  265.       MUIA_Application_Version    , "$VER: KMSAM " VERSION " (" __COMMODORE_DATE__ ")",
  266.       MUIA_Application_Copyright  , "©1994 Thomas Schwarz",
  267.       MUIA_Application_Author     , "Thomas Schwarz",
  268.       MUIA_Application_Description, "Manages Karfunkel Mailbox System Msg-Areas.",
  269.       MUIA_Application_Base       , "KMSAM",
  270.       MUIA_Application_Menu       , MenuList,
  271.       MUIA_Application_SingleTask , TRUE,
  272.       SubWindow, WI_Manager = WindowObject,
  273.          MUIA_Window_ID, MAKE_ID('M','A','I','N'),
  274.          MUIA_Window_Title, "KMS Area Manager",
  275.          WindowContents, VGroup,
  276.             Child, HGroup,
  277.                Child, VGroup,
  278.                   GroupFrameT("Areas"),
  279.                   /*
  280.                   Child, ST_Path = StringObject,
  281.                      StringFrame,
  282.                      MUIA_String_Reject, " ",
  283.                      MUIA_String_MaxLen, LEN_KMSPATH+1,
  284.                      End,
  285.                   */
  286.                   Child, ST_Path = TextObject,
  287.                      StringFrame,
  288.                      End,
  289.                   Child, LV_Areas = ListviewObject,
  290.                      MUIA_Listview_List, ListObject,
  291.                         InputListFrame,
  292.                         MUIA_List_DisplayHook, &list_dsphook,
  293.                         MUIA_List_CompareHook, &list_cmphook,
  294.                         End,
  295.                      End,
  296.                   Child, HGroup,
  297.                      MUIA_Group_SameSize, TRUE,
  298.                      Child, BT_Parent = KeyButton("Parent", 'p'),
  299.                      Child, HSpace(0),
  300.                      Child, BT_Child = KeyButton("Children", 'c'),
  301.                      End,
  302.                   End,
  303.                Child, VGroup,
  304.                   MUIA_Weight, 25,
  305.                   Child, VGroup,
  306.                      GroupFrameT("Menu"),
  307.                      Child, BT_Cut    = KeyButton("Cut"   , 't'),
  308.                      Child, BT_Copy   = KeyButton("Copy"  , 'o'),
  309.                      Child, BT_Paste  = KeyButton("Paste" , 'a'),
  310.                      End,
  311.                   Child, VGroup,
  312.                      GroupFrame,
  313.                      Child, BT_Add    = KeyButton("Insert", 'i'),
  314.                      Child, BT_Remove = KeyButton("Delete", 'l'),
  315.                      End,
  316.                   Child, VGroup,
  317.                      GroupFrame,
  318.                      Child, BT_Up     = KeyButton("Up"    , 'u'),
  319.                      Child, BT_Down   = KeyButton("Down"  , 'd'),
  320.                      End,
  321.                   Child, VGroup,
  322.                      GroupFrame,
  323.                      Child, BT_Sort   = KeyButton("Sort"  , 's'),
  324.                      End,
  325.                   Child, VGroup,
  326.                      GroupFrame,
  327.                      Child, BT_Edit   = KeyButton("Edit"  , 'e'),
  328.                      End,
  329.                   End,
  330.                End,
  331.             End,
  332.          End,
  333.       SubWindow, WI_Editor = WindowObject,
  334.          MUIA_Window_ID, MAKE_ID('E','D','I','T'),
  335.          MUIA_Window_Title, "KMS Area Editor",
  336.          WindowContents, VGroup,
  337.             Child, HGroup,
  338.                Child, VGroup,
  339.                   Child, ColGroup(2),
  340.                      Child, KeyLabel2("Area Name:", 'n'),
  341.                      Child, ST_Name = StringObject,
  342.                         StringFrame,
  343.                         MUIA_String_MaxLen, LEN_AREANAME+1,
  344.                         MUIA_ControlChar, 'n',
  345.                         End,
  346.                      Child, KeyLabel2("Area Info:", 'i'),
  347.                      Child, ST_Info = StringObject,
  348.                         StringFrame,
  349.                         MUIA_String_MaxLen, LEN_AREAINFO+1,
  350.                         MUIA_ControlChar, 'i',
  351.                         End,
  352.                      Child, KeyLabel2("UMS Group:", 'g'),
  353.                      Child, ST_MBName = StringObject,
  354.                         StringFrame,
  355.                         MUIA_String_MaxLen, LEN_MBNAME+1,
  356.                         MUIA_ControlChar, 'g',
  357.                         End,
  358.                      Child, KeyLabel2("Binary Path:", 'b'),
  359.                      Child, ST_FilePath = StringObject,
  360.                         StringFrame,
  361.                         MUIA_String_MaxLen, LEN_FILEAREA+1,
  362.                         MUIA_ControlChar, 'b',
  363.                         End,
  364.                      End,
  365.                   Child, HGroup,
  366.                      Child, Label2("HoldNum:"),
  367.                      Child, ST_HoldNum = StringObject,
  368.                         StringFrame,
  369.                         MUIA_String_MaxLen, 5,
  370.                         MUIA_String_Accept, "0123456789",
  371.                         MUIA_String_Integer, 0,
  372.                         End,
  373.                      Child, Label2("HoldDays:"),
  374.                      Child, ST_HoldDays = StringObject,
  375.                         StringFrame,
  376.                         MUIA_String_MaxLen, 5,
  377.                         MUIA_String_Accept, "0123456789",
  378.                         MUIA_String_Integer, 0,
  379.                         End,
  380.                      End,
  381.                   Child, VSpace(0),
  382.                   Child, HGroup,
  383.                      Child, HSpace(0),
  384.                      Child, ColGroup(2),
  385.                         Child, Label1("Group:"),
  386.                         Child, CH_Group = CheckMark(FALSE),
  387.                         Child, Label1("To:"),
  388.                         Child, CH_ToName = CheckMark(FALSE),
  389.                         End,
  390.                      Child, HSpace(0),
  391.                      Child, ColGroup(2),
  392.                         Child, Label1("Re:"),
  393.                         Child, CH_NoRe = CheckMark(FALSE),
  394.                         Child, Label1("Pseudos:"),
  395.                         Child, CH_Pseudos = CheckMark(FALSE),
  396.                         End,
  397.                      Child, HSpace(0),
  398.                      End,
  399.                   Child, VSpace(0),
  400.                   Child, ColGroup(2),
  401.                      Child, KeyLabel2("Type:", 't'),
  402.                      Child, PG_AType = PageGroup,
  403.                         Child, CY_ATypeRoot = CycleObject,
  404.                            MUIA_Cycle_Entries, CYA_ATypeRoot,
  405.                            MUIA_ControlChar, 't',
  406.                            End,
  407.                         Child, CY_ATypePublic = CycleObject,
  408.                            MUIA_Cycle_Entries, CYA_ATypePublic,
  409.                            MUIA_ControlChar, 't',
  410.                            End,
  411.                         End,
  412.                      End,
  413.                   Child, VSpace(0),
  414.                   End,
  415.                Child, HSpace(10),
  416.                Child, VGroup,
  417.                   Child, ColGroup(2),
  418.                      GroupFrameT("Access Levels"),
  419.                      Child, Label2("Read:"),
  420.                      Child, SL_RLevel = SliderObject,
  421.                         MUIA_Group_Horiz , TRUE,
  422.                         MUIA_Slider_Min  , 0,
  423.                         MUIA_Slider_Max  , 255,
  424.                         MUIA_Slider_Level, 0,
  425.                         End,
  426.                      Child, Label2("Write:"),
  427.                      Child, SL_WLevel = SliderObject,
  428.                         MUIA_Group_Horiz , TRUE,
  429.                         MUIA_Slider_Min  , 0,
  430.                         MUIA_Slider_Max  , 255,
  431.                         MUIA_Slider_Level, 0,
  432.                         End,
  433.                      Child, Label2("Edit:"),
  434.                      Child, SL_ELevel = SliderObject,
  435.                         MUIA_Group_Horiz , TRUE,
  436.                         MUIA_Slider_Min  , 0,
  437.                         MUIA_Slider_Max  , 255,
  438.                         MUIA_Slider_Level, 0,
  439.                         End,
  440.                      End,
  441.                   Child, VGroup,
  442.                      GroupFrameT("Access Bits"),
  443.                      Child, LV_AccBits = ListviewObject,
  444.                         MUIA_Listview_MultiSelect, TRUE,
  445.                         MUIA_Listview_List, ListObject,
  446.                            InputListFrame,
  447.                            End,
  448.                         End,
  449.                      Child, ST_AccBit = StringObject,
  450.                         StringFrame,
  451.                         MUIA_String_Reject, " ",
  452.                         MUIA_String_MaxLen, LEN_ACCBITNAME+1,
  453.                         MUIA_String_AttachedList, LV_AccBits,
  454.                         End,
  455.                      End,
  456.                   End,
  457.                End,
  458.             Child, HGroup,
  459.                Child, HSpace(0),
  460.                Child, HSpace(0),
  461.                End,
  462.             Child, ColGroup(4),
  463.                Child, Label1("Quote:"),
  464.                Child, ST_QuoteStr = StringObject,
  465.                   StringFrame,
  466.                   MUIA_String_MaxLen, 3,
  467.                   MUIA_String_Accept, "0123456789",
  468.                   MUIA_String_Integer, 0,
  469.                   End,
  470.                Child, Label1("PQuote:"),
  471.                Child, ST_PQuoteStr = StringObject,
  472.                   StringFrame,
  473.                   MUIA_String_MaxLen, 3,
  474.                   MUIA_String_Accept, "0123456789",
  475.                   MUIA_String_Integer, 0,
  476.                   End,
  477.                Child, Label1("Resend:"),
  478.                Child, ST_ResendStr = StringObject,
  479.                   StringFrame,
  480.                   MUIA_String_MaxLen, 3,
  481.                   MUIA_String_Accept, "0123456789",
  482.                   MUIA_String_Integer, 0,
  483.                   End,
  484.                Child, Label1("Forward:"),
  485.                Child, ST_ForwardStr = StringObject,
  486.                   StringFrame,
  487.                   MUIA_String_MaxLen, 3,
  488.                   MUIA_String_Accept, "0123456789",
  489.                   MUIA_String_Integer, 0,
  490.                   End,
  491.                Child, Label1("Origin:"),
  492.                Child, ST_OriginStr = StringObject,
  493.                   StringFrame,
  494.                   MUIA_String_MaxLen, 3,
  495.                   MUIA_String_Accept, "0123456789",
  496.                   MUIA_String_Integer, 0,
  497.                   End,
  498.                End,
  499.             Child, HGroup,
  500.                MUIA_Group_SameSize, TRUE,
  501.                Child, BT_EUse    = KeyButton("Ok"    , 'o'),
  502.                Child, HSpace(0),
  503.                Child, BT_ECancel = KeyButton("Cancel", 'c'),
  504.                End,
  505.             End,
  506.          End,
  507.       End;
  508.  
  509.    if (!App)
  510.       Sense(App, "Failed to create application.");
  511.  
  512.    DoMethod(WI_Manager, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, App, 2, MUIM_Application_ReturnID, MID_OK);
  513.    /*
  514.    DoMethod(ST_Path   , MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, App, 2, MUIM_Application_ReturnID, MID_PATH);
  515.    */
  516.    DoMethod(LV_Areas  , MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, App, 2, MUIM_Application_ReturnID, MID_DOUBLE);
  517.    DoMethod(LV_Areas  , MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, App, 2, MUIM_Application_ReturnID, MID_SELAREA);
  518.    DoMethod(BT_Up     , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_UP);
  519.    DoMethod(BT_Down   , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_DOWN);
  520.    DoMethod(BT_Parent , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_PARENT);
  521.    DoMethod(BT_Child  , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_CHILD);
  522.    DoMethod(BT_Cut    , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_CUT);
  523.    DoMethod(BT_Copy   , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_COPY);
  524.    DoMethod(BT_Paste  , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_PASTE);
  525.    DoMethod(BT_Add    , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_ADD);
  526.    DoMethod(BT_Remove , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_REMOVE);
  527.    DoMethod(BT_Sort   , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_SORT);
  528.    DoMethod(BT_Edit   , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, MID_EDIT);
  529.  
  530.    DoMethod(WI_Manager, MUIM_Window_SetCycleChain, /* ST_Path, */ LV_Areas,
  531.             BT_Parent, BT_Child, BT_Cut, BT_Copy, BT_Paste, BT_Add, BT_Remove,
  532.             BT_Up, BT_Down, BT_Sort, BT_Edit, NULL);
  533.  
  534.    set(WI_Manager, MUIA_Window_DefaultObject, LV_Areas);
  535.  
  536.    DoMethod(WI_Editor , MUIM_Notify, MUIA_Window_CloseRequest, TRUE, App, 2, MUIM_Application_ReturnID, EID_CANCEL);
  537.    DoMethod(BT_EUse   , MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, EID_USE);
  538.    DoMethod(BT_ECancel, MUIM_Notify, MUIA_Pressed, FALSE, App, 2, MUIM_Application_ReturnID, EID_CANCEL);
  539.    DoMethod(LV_AccBits, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, App, 2, MUIM_Application_ReturnID, EID_SELAB);
  540.    DoMethod(ST_AccBit , MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, App, 2, MUIM_Application_ReturnID, EID_NAMEAB);
  541.    DoMethod(CY_ATypePublic, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, App, 2, MUIM_Application_ReturnID, EID_CGTYPE);
  542.  
  543.    DoMethod(WI_Editor, MUIM_Window_SetCycleChain,
  544.             ST_Name, ST_Info, ST_MBName, ST_FilePath, ST_HoldNum, ST_HoldDays,
  545.             CH_Group, CH_ToName, CH_NoRe, CH_Pseudos, SL_RLevel, SL_WLevel,
  546.             SL_ELevel, CY_ATypeRoot, CY_ATypePublic, LV_AccBits, ST_AccBit,
  547.             ST_QuoteStr, ST_PQuoteStr, ST_ResendStr, ST_ForwardStr,
  548.             ST_OriginStr, BT_EUse, BT_ECancel, NULL);
  549.  
  550.    set(WI_Editor, MUIA_Window_DefaultObject, LV_AccBits);
  551.  
  552.    STRPTR entry;
  553.    UBYTE n;
  554.    for(n = 0; n < 32; n++)
  555.       {
  556.       entry = AccBitNames[n];
  557.       DoMethod(LV_AccBits, MUIM_List_Insert, &entry, 1, MUIV_List_Insert_Bottom);
  558.       }
  559.  
  560.    if (Areaname)
  561.       {
  562.       TakeASem(FALSE);
  563.       CurrentMother = NULL;
  564.       CurrentArea = ResolvePath(Areaname);
  565.       UpdatePath();
  566.       DropASem();
  567.  
  568.       if (!CurrentArea)
  569.          {
  570.          if (!CurrentMother)
  571.             {
  572.             MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Invalid path specification.", NULL);
  573.             Sense(App, NULL);
  574.             }
  575.          else if (!MUI_RequestA(App, NULL, 0, "KMSAM Error", "Create|Abort", "Area does not exist.", NULL))
  576.             Sense(App, NULL);
  577.          }
  578.  
  579.       TakeASem(FALSE);
  580.       index = DisplayDir(CurrentMother, CurrentArea);
  581.       DropASem();
  582.       set(LV_Areas, MUIA_List_Active, index);
  583.  
  584.       if (CurrentArea)
  585.          DoMethod(App, MUIM_Application_ReturnID, MID_EDIT);
  586.       else
  587.          DoMethod(App, MUIM_Application_ReturnID, MID_ADD);
  588.       }
  589.    else
  590.       {
  591.       TakeASem(FALSE);
  592.       CurrentMother = NULL;
  593.       CurrentArea = SetArea(1);
  594.       UpdatePath();
  595.       index = DisplayDir(CurrentMother, CurrentArea);
  596.       DropASem();
  597.       set(LV_Areas, MUIA_List_Active, index);
  598.  
  599.       ULONG open;
  600.       set(WI_Manager, MUIA_Window_Open, TRUE);
  601.       get(WI_Manager, MUIA_Window_Open, &open);
  602.       if (!open)
  603.          Sense(App, "Failed to open window.");
  604.    
  605.       DoMethod(WI_Manager, MUIM_Window_ScreenToFront,);
  606.       }
  607.  
  608.    while(running)
  609.       {
  610.       switch(DoMethod(App, MUIM_Application_Input, &signal))
  611.          {
  612.          case MID_ABOUT:
  613.             MUI_RequestA(App, NULL, 0, "Information", "Ok",
  614.                          eC ePW "KMS Area Manager\n\n"
  615.                          ePB "Version " VERSION " (" __COMMODORE_DATE__ ")\n"
  616.                          "Copyright 1994 by Thomas Schwarz.\n"
  617.                          "\nThis is a MUI-Application.\n"
  618.                          "MUI is copyrighted by Stefan Stuntz.", NULL);
  619.  
  620.             break;
  621.  
  622.          case MID_COPY:
  623.             if (!CurrentMother)
  624.                {
  625.                DisplayBeep(0);
  626.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Function inoperable in root area!", NULL);
  627.                break;
  628.                }
  629.  
  630.             DoMethod(LV_Areas, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &an);
  631.             if (an)
  632.                {
  633.                if (an->AreaData.Daughter)
  634.                   {
  635.                   MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Not possible for parent areas.", NULL);
  636.                   break;
  637.                   }
  638.  
  639.                AreaStore = an->AreaData;
  640.                }
  641.             else
  642.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Copy failed!", NULL);
  643.  
  644.             break;
  645.  
  646.          case MID_UP:
  647.             get(LV_Areas, MUIA_List_Entries, &entries);
  648.             get(LV_Areas, MUIA_List_Active, &num);
  649.             if (num != MUIV_List_Active_Off && num > 0)
  650.                {
  651.                if (num > 1)
  652.                   DoMethod(LV_Areas, MUIM_List_GetEntry, num-2, &an);
  653.                else
  654.                   an = NULL;
  655.                DoMethod(LV_Areas, MUIM_List_GetEntry, num-1, &an2);
  656.                DoMethod(LV_Areas, MUIM_List_GetEntry, num, &an3);
  657.  
  658.                TakeASem(TRUE);
  659.                if (an)
  660.                   an->AreaData.Next = an3->AreaData.ID;
  661.                else
  662.                   CurrentMother->AreaData.Daughter = an3->AreaData.ID;
  663.                idmerk = an3->AreaData.Next;
  664.                an3->AreaData.Next = an2->AreaData.ID;
  665.                an2->AreaData.Next = idmerk;
  666.                DropASem();
  667.  
  668.                DoMethod(LV_Areas, MUIM_List_Exchange, num, num-1);
  669.                set(LV_Areas, MUIA_List_Active, MUIV_List_Active_Up);
  670.  
  671.                areaschanged = TRUE;
  672.                }
  673.             else
  674.                DisplayBeep(0);
  675.             
  676.             break;
  677.  
  678.          case MID_DOWN:
  679.             get(LV_Areas, MUIA_List_Entries, &entries);
  680.             get(LV_Areas, MUIA_List_Active, &num);
  681.             if (num != MUIV_List_Active_Off && num < entries-1)
  682.                {
  683.                if (num > 0)
  684.                   DoMethod(LV_Areas, MUIM_List_GetEntry, num-1, &an);
  685.                else
  686.                   an = NULL;
  687.                DoMethod(LV_Areas, MUIM_List_GetEntry, num, &an2);
  688.                DoMethod(LV_Areas, MUIM_List_GetEntry, num+1, &an3);
  689.  
  690.                TakeASem(TRUE);
  691.                if (an)
  692.                   an->AreaData.Next = an3->AreaData.ID;
  693.                else
  694.                   CurrentMother->AreaData.Daughter = an3->AreaData.ID;
  695.                idmerk = an3->AreaData.Next;
  696.                an3->AreaData.Next = an2->AreaData.ID;
  697.                an2->AreaData.Next = idmerk;
  698.                DropASem();
  699.  
  700.                DoMethod(LV_Areas, MUIM_List_Exchange, num, num+1);
  701.                set(LV_Areas, MUIA_List_Active, MUIV_List_Active_Down);
  702.  
  703.                areaschanged = TRUE;
  704.                }
  705.             else
  706.                DisplayBeep(0);
  707.             
  708.             break;
  709.  
  710.          case MID_PASTE:
  711.             if (!CurrentMother)
  712.                {
  713.                DisplayBeep(0);
  714.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Function inoperable in root area!", NULL);
  715.                break;
  716.                }
  717.  
  718.             if (!AreaStore.ID)
  719.                {
  720.                DisplayBeep(0);
  721.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Paste buffer is empty!", NULL);
  722.                break;
  723.                }
  724.  
  725.             TakeASem(TRUE);
  726.             an = AddAN();
  727.             if (an)
  728.                {
  729.                /* Areadaten übernehmen */
  730.  
  731.                idmerk = an->AreaData.ID;
  732.                an->AreaData = AreaStore;
  733.                an->AreaData.ID = idmerk;
  734.                an->AreaData.Next = 0;
  735.                an->AreaData.Mother = 0;
  736.  
  737.                if (an2 = SetArea(an->AreaData.Daughter))
  738.                   {
  739.                   an2->AreaData.Mother = idmerk;
  740.                   while(an2 = SetArea(an2->AreaData.Next))
  741.                      an2->AreaData.Mother = idmerk;
  742.                   }
  743.  
  744.                /* Area in Liste aufnehmen */
  745.  
  746.                LONG index = InsertArea(an);
  747.  
  748.                DoMethod(LV_Areas, MUIM_List_Insert, &an, 1, index);
  749.                set(LV_Areas, MUIA_List_Active, index);
  750.  
  751.                areaschanged = TRUE;
  752.                }
  753.             else
  754.                DisplayBeep(0);
  755.             DropASem();
  756.  
  757.             break;
  758.  
  759.          case MID_ADD:
  760.             if (!CurrentMother)
  761.                {
  762.                DisplayBeep(0);
  763.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Function inoperable in root area!", NULL);
  764.                break;
  765.                }
  766.  
  767.             TakeASem(TRUE);
  768.             an = AddAN();
  769.             if (an)
  770.                {
  771.                addflag = TRUE;
  772.  
  773.                if (Areaname)
  774.                   {
  775.                   STRPTR sp = Areaname + strlen(Areaname);
  776.                   while(sp != Areaname && *sp != '/')
  777.                      sp--;
  778.                   if (*sp == '/')
  779.                      sp++;
  780.  
  781.                   Upper(sp);
  782.                   strcpy(an->AreaData.Name, sp);
  783.                   }
  784.                else
  785.                   *an->AreaData.Name = '\0';
  786.  
  787.                an->AreaData.Type = ATYPE_NEWS;
  788.                an->AreaData.EditLevel = 255;
  789.                an->AreaData.QuoteStr = 1;
  790.                an->AreaData.PQuoteStr = 1;
  791.                an->AreaData.ResendStr = 1;
  792.                an->AreaData.ForwardStr = 1;
  793.                an->AreaData.OriginStr = 1;
  794.  
  795.                DoMethod(App, MUIM_Application_ReturnID, MID_EDIT);
  796.                }
  797.             else if (Areaname)
  798.                {
  799.                DisplayBeep(0);
  800.                DoMethod(App, MUIM_Application_ReturnID, MID_OK);
  801.                }
  802.             else
  803.                DisplayBeep(0);
  804.  
  805.             DropASem();
  806.  
  807.             break;
  808.  
  809.          case MID_CUT:
  810.             if (!CurrentMother)
  811.                {
  812.                DisplayBeep(0);
  813.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Can't cut root area!", NULL);
  814.                break;
  815.                }
  816.             
  817.             cut = TRUE;
  818.  
  819.          case MID_REMOVE:
  820.             if (!CurrentMother)
  821.                {
  822.                DisplayBeep(0);
  823.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Can't remove root area!", NULL);
  824.                break;
  825.                }
  826.  
  827.             DoMethod(LV_Areas, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &an);
  828.             if (an)
  829.                {
  830.                /* Wenn Area momentan CurrentArea eines Users, nicht löschen */
  831.  
  832.                TakeMSem(FALSE);
  833.                struct KMSNode *member = KMSBase->MemberList.mlh_Head;
  834.                error = FALSE;
  835.                while(!error && member->Node.mln_Succ)
  836.                   {
  837.                   if (member->LCPtr->Session.CurrentArea == an)
  838.                      {
  839.                      MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Area currently in use!", NULL);
  840.                      error = TRUE;
  841.                      }
  842.                   member = member->Node.mln_Succ;
  843.                   }
  844.                DropMSem();
  845.  
  846.                /* Wirklich löschen? */
  847.  
  848.                if (!error && !cut)
  849.                   if (!MUI_RequestA(App, NULL, 0, "KMSAM Request", "Just do it!|Oh no!", "Really delete area?", NULL))
  850.                      error = TRUE;
  851.  
  852.                if (!error)
  853.                   {
  854.                   if (cut)
  855.                      AreaStore = an->AreaData;
  856.                   
  857.                   TakeASem(TRUE);
  858.                   RemoveArea(an);
  859.                   DeleteAN(an);
  860.  
  861.                   DoMethod(LV_Areas, MUIM_List_Remove, MUIV_List_Remove_Active);
  862.                   DoMethod(LV_Areas, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &CurrentArea);
  863.  
  864.                   UpdatePath();
  865.                   DropASem();
  866.  
  867.                   areaschanged = TRUE;
  868.                   }
  869.                }
  870.             else
  871.                DisplayBeep(0);
  872.  
  873.             cut = FALSE;
  874.             
  875.             break;
  876.  
  877.          case MID_SORT:
  878.             struct AreaNode *next, *last;
  879.             LONG n = 0;
  880.  
  881.             if (!CurrentArea)
  882.                MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "There's nothing there to be sorted!", NULL);
  883.             else
  884.                {
  885.                TakeASem(TRUE);
  886.  
  887.                DoMethod(LV_Areas, MUIM_List_Sort,);
  888.  
  889.                DoMethod(LV_Areas, MUIM_List_GetEntry, n++, &next);
  890.                last = next;
  891.                if (next)
  892.                   CurrentMother->AreaData.Daughter = next->AreaData.ID;
  893.  
  894.                while(next)
  895.                   {
  896.                   last = next;
  897.  
  898.                   DoMethod(LV_Areas, MUIM_List_GetEntry, n++, &next);
  899.                   if (next)
  900.                      last->AreaData.Next = next->AreaData.ID;
  901.                   }
  902.  
  903.                if (last)
  904.                   last->AreaData.Next = 0;
  905.  
  906.                set(LV_Areas, MUIA_List_Active, 0);
  907.                areaschanged = TRUE;
  908.  
  909.                DropASem();
  910.                }
  911.  
  912.             break;
  913.  
  914.          case MID_EDIT:
  915.             if (!addflag)
  916.                DoMethod(LV_Areas, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &an);
  917.  
  918.             if (an)
  919.                {
  920.                area = an->AreaData;
  921.  
  922.                set(ST_Name, MUIA_String_Contents, area.Name);
  923.                set(ST_Info, MUIA_String_Contents, area.Info);
  924.                set(ST_MBName, MUIA_String_Contents, area.MBName);
  925.                set(ST_FilePath, MUIA_String_Contents, area.FilePath);
  926.                set(ST_QuoteStr, MUIA_String_Integer, area.QuoteStr);
  927.                set(ST_PQuoteStr, MUIA_String_Integer, area.PQuoteStr);
  928.                set(ST_ResendStr, MUIA_String_Integer, area.ResendStr);
  929.                set(ST_ForwardStr, MUIA_String_Integer, area.ForwardStr);
  930.                set(ST_OriginStr, MUIA_String_Integer, area.OriginStr);
  931.                set(SL_RLevel, MUIA_Slider_Level, area.ReadLevel);
  932.                set(SL_WLevel, MUIA_Slider_Level, area.WriteLevel);
  933.                set(SL_ELevel, MUIA_Slider_Level, area.EditLevel);
  934.                set(ST_HoldNum, MUIA_String_Integer, area.HoldNum);
  935.                set(ST_HoldDays, MUIA_String_Integer, area.HoldDays);
  936.  
  937.                for(num = 0; num < 32; num++)
  938.                   DoMethod(LV_AccBits, MUIM_List_Select, num, MUIV_List_Select_Off, NULL);
  939.  
  940.                num = 0;
  941.                acc = area.AccessBits;
  942.                while(acc)
  943.                   {
  944.                   if (acc & 1)
  945.                      DoMethod(LV_AccBits, MUIM_List_Select, num, MUIV_List_Select_On, NULL);
  946.  
  947.                   acc = acc / 2;
  948.                   num++;
  949.                   }
  950.  
  951.                set(CH_Group, MUIA_Selected, (area.Type & ATYPE_GROUP) ? TRUE : FALSE);
  952.                set(CH_NoRe, MUIA_Selected, (area.WriteFlag & AWF_NORE) ? FALSE : TRUE);
  953.                set(CH_Pseudos, MUIA_Selected, (area.WriteFlag & AWF_PSEUDO) ? TRUE : FALSE);
  954.                set(CH_ToName, MUIA_Selected, (area.WriteFlag & AWF_TONAME) ? TRUE : FALSE);
  955.  
  956.                if (area.ID == 1)
  957.                   {
  958.                   set(ST_MBName, MUIA_Disabled, TRUE);
  959.                   set(CH_Group, MUIA_Disabled, TRUE);
  960.                   set(CH_ToName, MUIA_Selected, TRUE);
  961.                   set(CH_ToName, MUIA_Disabled, TRUE);
  962.                   set(ST_FilePath, MUIA_Disabled, FALSE);
  963.                   set(PG_AType, MUIA_Group_ActivePage, 0);
  964.                   }
  965.                else
  966.                   {
  967.                   set(ST_MBName, MUIA_Disabled, FALSE);
  968.                   set(CH_Group, MUIA_Disabled, FALSE);
  969.                   set(CH_ToName, MUIA_Disabled, FALSE);
  970.                   set(PG_AType, MUIA_Group_ActivePage, 1);
  971.                   num = 0;
  972.                   if (area.Type & ATYPE_FILES)
  973.                      {
  974.                      set(ST_FilePath, MUIA_Disabled, FALSE);
  975.                      num = 1;
  976.                      }
  977.                   else
  978.                      set(ST_FilePath, MUIA_Disabled, TRUE);
  979.  
  980.                   set(CY_ATypePublic, MUIA_Cycle_Active, num);
  981.                   }
  982.  
  983.                ULONG edopen;
  984.                set(WI_Editor, MUIA_Window_Open, TRUE);
  985.                get(WI_Editor, MUIA_Window_Open, &edopen);
  986.                if (!edopen)
  987.                   {
  988.                   MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Couldn't open window!", NULL);
  989.                   if (addflag)
  990.                      {
  991.                      TakeASem(TRUE);
  992.                      DeleteAN(an);
  993.                      DropASem();
  994.                      }
  995.                   addflag = FALSE;
  996.                   if (Areaname)
  997.                      DoMethod(App, MUIM_Application_ReturnID, MID_OK);
  998.                   }
  999.                else
  1000.                   set(WI_Manager, MUIA_Window_Sleep, TRUE);
  1001.  
  1002.                DoMethod(WI_Editor, MUIM_Window_ScreenToFront,);
  1003.                }
  1004.             else
  1005.                {
  1006.                DisplayBeep(0);
  1007.                if (Areaname)
  1008.                   DoMethod(App, MUIM_Application_ReturnID, MID_OK);
  1009.                }
  1010.  
  1011.             break;
  1012.  
  1013.          case MID_OK:
  1014.          case MUIV_Application_ReturnID_Quit:
  1015.             if (addflag)
  1016.                {
  1017.                TakeASem(TRUE);
  1018.                DeleteAN(an);
  1019.                DropASem();
  1020.                }
  1021.             addflag = FALSE;
  1022.  
  1023.             CleanUpAreaList();
  1024.  
  1025.             if (!Areaname || !FindPort("KMS"))
  1026.                {
  1027.                set(App, MUIA_Application_Sleep, TRUE);
  1028.                if (areaschanged)
  1029.                   {
  1030.                   if (!WriteAreaList())
  1031.                      MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Saving arealist failed!", NULL);
  1032.                   }
  1033.                if (bitschanged)
  1034.                   {
  1035.                   if (!WriteAccBits())
  1036.                      MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Saving access bits failed!", NULL);
  1037.                   }
  1038.                set(App, MUIA_Application_Sleep, FALSE);
  1039.                }
  1040.             else if (areaschanged)
  1041.                KMSBase->Modified |= MODIFIED_AREAS;
  1042.  
  1043.             running = FALSE;
  1044.  
  1045.             break;
  1046.  
  1047.          case MID_CHILD:
  1048.          case MID_DOUBLE:
  1049.             DoMethod(LV_Areas, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &an);
  1050.             if (an)
  1051.                {
  1052.                TakeASem(FALSE);
  1053.  
  1054.                if (an->AreaData.Daughter)
  1055.                   {
  1056.                   CurrentMother = an;
  1057.                   CurrentArea = SetArea(an->AreaData.Daughter);
  1058.                   index = DisplayDir(CurrentMother, CurrentArea);
  1059.                   set(LV_Areas, MUIA_List_Active, index);
  1060.                   }
  1061.                else
  1062.                   {
  1063.                   CurrentMother = an;
  1064.                   CurrentArea = NULL;
  1065.                   DisplayDir(CurrentMother, CurrentArea);
  1066.                   }
  1067.  
  1068.                UpdatePath();
  1069.  
  1070.                DropASem();
  1071.                }
  1072.             else
  1073.                DisplayBeep(0);
  1074.  
  1075.             break;
  1076.  
  1077.          case MID_PARENT:
  1078.             if (CurrentMother)
  1079.                {
  1080.                TakeASem(FALSE);
  1081.  
  1082.                CurrentArea = CurrentMother;
  1083.                CurrentMother = SetArea(CurrentMother->AreaData.Mother);
  1084.                index = DisplayDir(CurrentMother, CurrentArea);
  1085.                set(LV_Areas, MUIA_List_Active, index);
  1086.  
  1087.                DropASem();
  1088.                }
  1089.             else
  1090.                DisplayBeep(0);
  1091.  
  1092.             break;
  1093.  
  1094.          case MID_SELAREA:
  1095.             set(WI_Manager, MUIA_Window_ActiveObject, LV_Areas);
  1096.             DoMethod(LV_Areas, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &CurrentArea);
  1097.             TakeASem(FALSE);
  1098.             UpdatePath();
  1099.             DropASem();
  1100.  
  1101.             break;
  1102.  
  1103.          case EID_SELAB:
  1104.             set(WI_Editor, MUIA_Window_ActiveObject, LV_AccBits);
  1105.             get(LV_AccBits, MUIA_List_Active, &num);
  1106.             set(ST_AccBit, MUIA_String_Contents, AccBitNames[num]);
  1107.  
  1108.             break;
  1109.  
  1110.          case EID_NAMEAB:
  1111.             STRPTR text;
  1112.             get(LV_AccBits, MUIA_List_Active, &num);
  1113.             get(ST_AccBit, MUIA_String_Contents, &text);
  1114.             strcpy(AccBitNames[num], text);
  1115.             DoMethod(LV_AccBits, MUIM_List_Redraw, MUIV_List_Redraw_Active);
  1116.  
  1117.             bitschanged = TRUE;
  1118.  
  1119.             break;
  1120.  
  1121.          case EID_CGTYPE:
  1122.             get(CY_ATypePublic, MUIA_Cycle_Active, &num);
  1123.             if (num == 0) /* News */
  1124.                {
  1125.                set(ST_FilePath, MUIA_String_Contents, "");
  1126.                set(ST_FilePath, MUIA_Disabled, TRUE);
  1127.                }
  1128.             else if (num == 1) /* Binary */
  1129.                set(ST_FilePath, MUIA_Disabled, FALSE);
  1130.  
  1131.             break;
  1132.  
  1133.          case EID_USE:
  1134.             STRPTR text;
  1135.             ULONG value;
  1136.  
  1137.             get(ST_Name, MUIA_String_Contents, &text);
  1138.             strcpy(area.Name, text);
  1139.             Upper(area.Name);
  1140.             get(ST_Info, MUIA_String_Contents, &text);
  1141.             strcpy(area.Info, text);
  1142.             get(ST_MBName, MUIA_String_Contents, &text);
  1143.             strcpy(area.MBName, text);
  1144.             get(ST_FilePath, MUIA_String_Contents, &text);
  1145.             strcpy(area.FilePath, text);
  1146.             get(ST_QuoteStr, MUIA_String_Integer, &value);
  1147.             area.QuoteStr = value;
  1148.             get(ST_PQuoteStr, MUIA_String_Integer, &value);
  1149.             area.PQuoteStr = value;
  1150.             get(ST_ResendStr, MUIA_String_Integer, &value);
  1151.             area.ResendStr = value;
  1152.             get(ST_ForwardStr, MUIA_String_Integer, &value);
  1153.             area.ForwardStr = value;
  1154.             get(ST_OriginStr, MUIA_String_Integer, &value);
  1155.             area.OriginStr = value;
  1156.             get(SL_RLevel, MUIA_Slider_Level, &value);
  1157.             area.ReadLevel = (UWORD)value;
  1158.             get(SL_WLevel, MUIA_Slider_Level, &value);
  1159.             area.WriteLevel = (UWORD)value;
  1160.             get(SL_ELevel, MUIA_Slider_Level, &value);
  1161.             area.EditLevel = (UWORD)value;
  1162.             get(ST_HoldNum, MUIA_String_Integer, &value);
  1163.             area.HoldNum = value;
  1164.             get(ST_HoldDays, MUIA_String_Integer, &value);
  1165.             area.HoldDays = value;
  1166.  
  1167.             acc = 1;
  1168.             area.AccessBits = 0;
  1169.             for(num = 0; num < 32; num++)
  1170.                {
  1171.                DoMethod(LV_AccBits, MUIM_List_Select, num, MUIV_List_Select_Ask, &state);
  1172.  
  1173.                if (state == MUIV_List_Select_On)
  1174.                   area.AccessBits |= acc;
  1175.  
  1176.                acc = acc << 1;
  1177.                }
  1178.  
  1179.             if (area.ID == 1)
  1180.                area.Type = ATYPE_PRIVATE;
  1181.             else
  1182.                {
  1183.                get(CY_ATypePublic, MUIA_Cycle_Active, &num);
  1184.                if (num == 0)
  1185.                   area.Type = ATYPE_NEWS;
  1186.                else if (num == 1)
  1187.                   area.Type = ATYPE_FILES;
  1188.                }
  1189.             get(CH_Group, MUIA_Selected, &num);
  1190.             if (num)
  1191.                area.Type |= ATYPE_GROUP;
  1192.             area.WriteFlag = 0;
  1193.             get(CH_ToName, MUIA_Selected, &num);
  1194.             if (num)
  1195.                area.WriteFlag |= AWF_TONAME;
  1196.             get(CH_NoRe, MUIA_Selected, &num);
  1197.             if (!num)
  1198.                area.WriteFlag |= AWF_NORE;
  1199.             get(CH_Pseudos, MUIA_Selected, &num);
  1200.             if (num)
  1201.                area.WriteFlag |= AWF_PSEUDO;
  1202.  
  1203.             Forbid();
  1204.             an->AreaData = area;
  1205.             Permit();
  1206.  
  1207.             if (addflag)
  1208.                {
  1209.                /* Area in Liste aufnehmen */
  1210.  
  1211.                TakeASem(TRUE);
  1212.                LONG index = InsertArea(an);
  1213.                DropASem();
  1214.  
  1215.                DoMethod(LV_Areas, MUIM_List_Insert, &an, 1, index);
  1216.                set(LV_Areas, MUIA_List_Active, index);
  1217.  
  1218.                addflag = FALSE;
  1219.                }
  1220.             else
  1221.                DoMethod(LV_Areas, MUIM_List_Redraw, MUIV_List_Redraw_Active);
  1222.  
  1223.             areaschanged = TRUE;
  1224.  
  1225.             // no break!
  1226.  
  1227.          case EID_CANCEL:
  1228.             if (addflag)
  1229.                {
  1230.                TakeASem(TRUE);
  1231.                DeleteAN(an);
  1232.                DropASem();
  1233.                }
  1234.             addflag = FALSE;
  1235.  
  1236.             set(WI_Editor, MUIA_Window_Open, FALSE);
  1237.             set(WI_Manager, MUIA_Window_Sleep, FALSE);
  1238.             TakeASem(FALSE);
  1239.             UpdatePath();
  1240.             DropASem();
  1241.  
  1242.             if (Areaname)
  1243.                DoMethod(App, MUIM_Application_ReturnID, MID_OK);
  1244.    
  1245.             break;
  1246.          }
  1247.  
  1248.       if (running && signal)
  1249.          Wait(signal);
  1250.       }
  1251.  
  1252.    Sense(App, NULL);
  1253.    }
  1254.  
  1255. ///
  1256.  
  1257. /************************************
  1258.  * DisplayDir: Directory anzeigen   *
  1259.  ************************************
  1260.  * I: CurrentMother, CurrentArea    *
  1261.  * O: Index CurrentArea in Listview *
  1262.  ************************************/
  1263.  
  1264. /// "DisplayDir"
  1265.  
  1266. LONG DisplayDir(struct AreaNode *mother, struct AreaNode *anode)
  1267.    {
  1268.    struct AreaNode *current;
  1269.    LONG result = MUIV_List_Active_Off;
  1270.    LONG count = 0;
  1271.  
  1272.    DoMethod(LV_Areas, MUIM_List_Clear,);
  1273.  
  1274.    /* Auf erste Tochter positionieren */
  1275.  
  1276.    if (mother)
  1277.       current = SetArea(mother->AreaData.Daughter);
  1278.    else
  1279.       current = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1280.  
  1281.    if (!current || !current->Node.mln_Succ)
  1282.       return result;
  1283.  
  1284.    set(LV_Areas, MUIA_List_Quiet, TRUE);
  1285.    do
  1286.       {
  1287.       DoMethod(LV_Areas, MUIM_List_Insert, ¤t, 1, MUIV_List_Insert_Bottom);
  1288.       if (current && current == anode)
  1289.          result = count;
  1290.       current = SetArea(current->AreaData.Next);
  1291.       count++;
  1292.       } while(current);
  1293.  
  1294.    set(LV_Areas, MUIA_List_Quiet, FALSE);
  1295.  
  1296.    return result;
  1297.    }
  1298.  
  1299. ///
  1300.  
  1301. /*********************************
  1302.  * AreaList einlesen             *
  1303.  *********************************
  1304.  * I: ---                        *
  1305.  * O: Erfolg? TRUE/FALSE         *
  1306.  *********************************/
  1307.  
  1308. /// "ReadAreaList"
  1309.  
  1310. BOOL ReadAreaList(VOID)
  1311.    {
  1312.    struct AreaNode *apoint;
  1313.    struct Area area;
  1314.    TEXT buffer[LEN_DOSPATH+1];
  1315.    TEXT buff[LEN_MBNAME+2]; /* MBNAME ist laengstes Element */
  1316.    FILE *file;
  1317.  
  1318.    /* Wenn schon eingelesen, fertig */
  1319.  
  1320.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1321.    if (apoint->Node.mln_Succ)
  1322.       return TRUE;
  1323.  
  1324.    /* Einlesen */
  1325.  
  1326.    ObtainSemaphore(&KMSBase->AreaSem);
  1327.  
  1328.    strcpy(buffer, KMSBase->DatDir);
  1329.    strcat(buffer, "KMS_AREAS.DAT");
  1330.  
  1331.    if (!(file = fopen(buffer, "r")))
  1332.       {
  1333.       ReleaseSemaphore(&KMSBase->AreaSem);
  1334.       return FALSE;
  1335.       }
  1336.    else
  1337.       {
  1338.       while(fgets(buff, LEN_AREANAME+2, file))
  1339.          {
  1340.          if (strlen(buff))
  1341.             buff[strlen(buff)-1] = '\0'; /* Linefeed am Ende entfernen */
  1342.  
  1343.          if (!(apoint = (struct AreaNode *)AllocMem((ULONG)sizeof(struct AreaNode),MEMF_PUBLIC|MEMF_CLEAR)))
  1344.             {
  1345.             Error("out of memory.");
  1346.  
  1347.             fclose(file);
  1348.  
  1349.             ReleaseSemaphore(&KMSBase->AreaSem);
  1350.             return FALSE;
  1351.             }
  1352.  
  1353.          clrmem(&area, sizeof(struct Area));
  1354.  
  1355.          strcpy(area.Name, buff);
  1356.          if (fgets(buff, LEN_AREAINFO+2, file))
  1357.             {
  1358.             if (strlen(buff))
  1359.                buff[strlen(buff)-1] = '\0'; /* Linefeed am Ende entfernen */
  1360.             strcpy(area.Info, buff);
  1361.             }
  1362.          if (fgets(buff, LEN_MBNAME+2, file))
  1363.             {
  1364.             if (strlen(buff))
  1365.                buff[strlen(buff)-1] = '\0';
  1366.             strcpy(area.MBName, buff);
  1367.             }
  1368.          if (fgets(buff, LEN_FILEAREA+2, file))
  1369.             {
  1370.             if (strlen(buff))
  1371.                buff[strlen(buff)-1] = '\0';
  1372.             strcpy(area.FilePath, buff);
  1373.             }
  1374.          if (fgets(buff, LEN_NUMBER+2, file))
  1375.             area.ID = (UWORD)atoi(buff);
  1376.          if (fgets(buff, LEN_NUMBER+2, file))
  1377.             area.Type = (UBYTE)atoi(buff);
  1378.          if (fgets(buff, LEN_NUMBER+2, file))
  1379.             area.ReadLevel = (UBYTE)atoi(buff);
  1380.          if (fgets(buff, LEN_NUMBER+2, file))
  1381.             area.WriteLevel = (UBYTE)atoi(buff);
  1382.          if (fgets(buff, LEN_NUMBER+2, file))
  1383.             area.EditLevel = (UBYTE)atoi(buff);
  1384.          if (fgets(buff, LEN_NUMBER+2, file))
  1385.             area.AccessBits = (ULONG)atol(buff);
  1386.          if (fgets(buff, LEN_NUMBER+2, file))
  1387.             area.WriteFlag = (UWORD)atol(buff);
  1388.          if (fgets(buff, LEN_NUMBER+2, file))
  1389.             area.QuoteStr = (UBYTE)atoi(buff);
  1390.          if (fgets(buff, LEN_NUMBER+2, file))
  1391.             area.PQuoteStr = (UBYTE)atoi(buff);
  1392.          if (fgets(buff, LEN_NUMBER+2, file))
  1393.             area.ResendStr = (UBYTE)atoi(buff);
  1394.          if (fgets(buff, LEN_NUMBER+2, file))
  1395.             area.ForwardStr = (UBYTE)atoi(buff);
  1396.          if (fgets(buff, LEN_NUMBER+2, file))
  1397.             area.OriginStr = (UBYTE)atoi(buff);
  1398.          if (fgets(buff, LEN_NUMBER+2, file))
  1399.             area.HoldNum = (UWORD)atoi(buff);
  1400.          if (fgets(buff, LEN_NUMBER+2, file))
  1401.             area.HoldDays = (UWORD)atoi(buff);
  1402.          if (fgets(buff, LEN_NUMBER+2, file))
  1403.             area.Mother = (UWORD)atoi(buff);
  1404.          if (fgets(buff, LEN_NUMBER+2, file))
  1405.             area.Daughter = (UWORD)atoi(buff);
  1406.          if (fgets(buff, LEN_NUMBER+2, file))
  1407.             area.Next = (UWORD)atoi(buff);
  1408.  
  1409.          apoint->AreaData = area;
  1410.  
  1411.          AddTail((struct List *)&KMSBase->AreaList, (struct Node *)apoint);
  1412.          }
  1413.       fclose(file);
  1414.       }
  1415.  
  1416.    ReleaseSemaphore(&KMSBase->AreaSem);
  1417.    return TRUE;
  1418.    }
  1419.  
  1420. ///
  1421.  
  1422. /*********************************
  1423.  * AreaList schreiben            *
  1424.  *********************************
  1425.  * I: ---                        *
  1426.  * O: Erfolg? TRUE/FALSE         *
  1427.  *********************************/
  1428.  
  1429. /// "WriteAreaList"
  1430.  
  1431. BOOL WriteAreaList(VOID)
  1432.    {
  1433.    struct AreaNode *apoint;
  1434.    TEXT buffer[LEN_DOSPATH+1];
  1435.    FILE *file;
  1436.  
  1437.    /* Daten werden nur im Besitz der Semaphore geschrieben */
  1438.  
  1439.    strcpy(buffer, KMSBase->DatDir);
  1440.    strcat(buffer, "KMS_AREAS.DAT");
  1441.  
  1442.    file = fopen(buffer, "w");
  1443.    if (!file)
  1444.       return FALSE;
  1445.  
  1446.    TakeASem(TRUE);
  1447.  
  1448.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1449.    while(apoint->Node.mln_Succ)
  1450.       {
  1451.       fprintf(file,"%s\n%s\n%s\n%s\n",     apoint->AreaData.Name,
  1452.                                            apoint->AreaData.Info,
  1453.                                            apoint->AreaData.MBName,
  1454.                                            apoint->AreaData.FilePath);
  1455.       fprintf(file,"%d\n%d\n%d\n%d\n%d\n", apoint->AreaData.ID,
  1456.                                            apoint->AreaData.Type,
  1457.                                            apoint->AreaData.ReadLevel,
  1458.                                            apoint->AreaData.WriteLevel,
  1459.                                            apoint->AreaData.EditLevel);
  1460.       fprintf(file,"%ld\n%d\n",            apoint->AreaData.AccessBits,
  1461.                                            apoint->AreaData.WriteFlag);
  1462.       fprintf(file,"%d\n%d\n%d\n%d\n%d\n", apoint->AreaData.QuoteStr,
  1463.                                            apoint->AreaData.PQuoteStr,
  1464.                                            apoint->AreaData.ResendStr,
  1465.                                            apoint->AreaData.ForwardStr,
  1466.                                            apoint->AreaData.OriginStr);
  1467.       fprintf(file,"%d\n",                 apoint->AreaData.HoldNum);
  1468.       fprintf(file,"%d\n",                 apoint->AreaData.HoldDays);
  1469.       fprintf(file,"%d\n%d\n%d\n",         apoint->AreaData.Mother,
  1470.                                            apoint->AreaData.Daughter,
  1471.                                            apoint->AreaData.Next);
  1472.  
  1473.       apoint = apoint->Node.mln_Succ;
  1474.       }
  1475.  
  1476.    fclose(file);
  1477.  
  1478.    DropASem();
  1479.  
  1480.    return TRUE;
  1481.    }
  1482.  
  1483. ///
  1484.  
  1485. /*********************************
  1486.  * Areadatei initialisieren      *
  1487.  *********************************
  1488.  * I: ---                        *
  1489.  * O: Erfolg TRUE/FALSE          *
  1490.  *********************************/
  1491.  
  1492. /// "InitAreaFile"
  1493.  
  1494. BOOL InitAreaFile(VOID)
  1495.    {
  1496.    TEXT buffer[LEN_DOSPATH+1];
  1497.    struct Area area;
  1498.    FILE *file;
  1499.  
  1500.    TakeASem(TRUE);
  1501.  
  1502.    strcpy(buffer, KMSBase->DatDir);
  1503.    strcat(buffer, "KMS_AREAS.DAT");
  1504.  
  1505.    if (!(file = fopen(buffer, "w")))
  1506.       {
  1507.       DropASem();
  1508.       return FALSE;
  1509.       }
  1510.  
  1511.    clrmem(&area, sizeof(struct Area));
  1512.  
  1513.    strcpy(area.Name, "PRIVAT");
  1514.    strcpy(area.Info, "- Private Mail -");
  1515.    strcpy(area.MBName, "");
  1516.    strcpy(area.FilePath, "KMS:Files/");
  1517.    area.ID = 1;
  1518.    area.Type = ATYPE_PRIVATE;
  1519.    area.ReadLevel = 1;
  1520.    area.WriteLevel = 1;
  1521.    area.EditLevel = 255;
  1522.    area.QuoteStr = 1;
  1523.    area.PQuoteStr = 1;
  1524.    area.ResendStr = 1;
  1525.    area.ForwardStr = 1;
  1526.    area.OriginStr = 1;
  1527.    area.HoldNum = 0;
  1528.    area.HoldDays = 0;
  1529.    fprintf(file, "%s\n%s\n%s\n%s\n",     area.Name,
  1530.                                          area.Info,
  1531.                                          area.MBName,
  1532.                                          area.FilePath);
  1533.    fprintf(file, "%d\n%d\n%d\n%d\n%d\n", area.ID,
  1534.                                          area.Type,
  1535.                                          area.ReadLevel,
  1536.                                          area.WriteLevel,
  1537.                                          area.EditLevel);
  1538.    fprintf(file, "%ld\n%d\n",            area.AccessBits,
  1539.                                          area.WriteFlag);
  1540.    fprintf(file, "%d\n%d\n%d\n%d\n%d\n", area.QuoteStr,
  1541.                                          area.PQuoteStr,
  1542.                                          area.ResendStr,
  1543.                                          area.ForwardStr,
  1544.                                          area.OriginStr);
  1545.    fprintf(file, "%d\n",                 area.HoldNum);
  1546.    fprintf(file, "%d\n",                 area.HoldDays);
  1547.    fprintf(file, "%d\n%d\n%d\n",         area.Mother,
  1548.                                          area.Daughter,
  1549.                                          area.Next);
  1550.  
  1551.    fclose(file);
  1552.  
  1553.    DropASem();
  1554.  
  1555.    return TRUE;
  1556.    }
  1557.  
  1558. ///
  1559.  
  1560. /********************************
  1561.  * Neuen AreaNode einrichten    *
  1562.  ********************************
  1563.  * I: ---                       *
  1564.  * O: struct AreaNode *         *
  1565.  ********************************/
  1566.  
  1567. /// "AddAN"
  1568.  
  1569. struct AreaNode *AddAN(VOID)
  1570.    {
  1571.    struct AreaNode *apoint, *newapoint;
  1572.    UWORD id = 0, previd = 0;
  1573.  
  1574.    /* Größte ID suchen */
  1575.  
  1576.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1577.    while(apoint->Node.mln_Succ)
  1578.       {
  1579.       if (apoint->AreaData.ID > previd)
  1580.          previd = apoint->AreaData.ID;
  1581.  
  1582.       apoint = apoint->Node.mln_Succ;
  1583.       }
  1584.  
  1585.    if (previd + 1 == 0) /* ID-Überlauf */
  1586.       {
  1587.       previd = 0; id = 0;
  1588.       apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1589.       if (apoint->Node.mln_Succ)
  1590.          id = apoint->AreaData.ID;
  1591.  
  1592.       while(apoint->Node.mln_Succ && previd + 1 == id)
  1593.          {
  1594.          previd = id;
  1595.  
  1596.          apoint = (struct AreaNode *)apoint->Node.mln_Succ;
  1597.          if (apoint->Node.mln_Succ)
  1598.             id = apoint->AreaData.ID;
  1599.          }
  1600.       }
  1601.  
  1602.    if (previd > 0 && previd == id)
  1603.       {
  1604.       MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Too many areas!", NULL);
  1605.       return NULL;
  1606.       }
  1607.  
  1608.    if (!(newapoint = (struct AreaNode *)AllocMem((ULONG)sizeof(struct AreaNode), MEMF_PUBLIC|MEMF_CLEAR)))
  1609.       {
  1610.       MUI_RequestA(App, NULL, 0, "KMSAM Error", "I see", "Out of memory!", NULL);
  1611.       return NULL;
  1612.       }
  1613.  
  1614.    newapoint->AreaData.ID = previd + 1;
  1615.  
  1616.    Insert((struct List *)&KMSBase->AreaList, (struct Node *)newapoint, (struct Node *)apoint->Node.mln_Pred);
  1617.  
  1618.    return newapoint;
  1619.    }
  1620.  
  1621. ///
  1622.  
  1623. /********************************
  1624.  * AreaNode löschen             *
  1625.  ********************************
  1626.  * I: struct AreaNode *         *
  1627.  * O: ---                       *
  1628.  ********************************/
  1629.  
  1630. /// "DeleteAN"
  1631.  
  1632. VOID DeleteAN(struct AreaNode *an)
  1633.    {
  1634.    if (!an)
  1635.       return;
  1636.  
  1637.    Remove((struct Node *)an);
  1638.  
  1639.    FreeMem(an, (ULONG)sizeof(struct AreaNode));
  1640.    }
  1641.  
  1642. ///
  1643.  
  1644. /****************************
  1645.  * Parse Arguments          *
  1646.  ****************************
  1647.  * I: ---                   *
  1648.  * O: Error: FALSE Ok: TRUE *
  1649.  ****************************/
  1650.  
  1651. /// "ParseArgs"
  1652.  
  1653. #define TEMPLATE "AREANAME"
  1654.  
  1655. STRPTR HelpTxt = "\nUsage:\n\nAREANAME      optional: Area to edit (May be complete KMS path)\n\n";
  1656.  
  1657. BOOL ParseArgs(VOID)
  1658.    {
  1659.    UBYTE n;
  1660.    ULONG args[1];
  1661.    struct RDArgs *rargs = NULL;
  1662.    struct RDArgs *myrdargs = NULL;
  1663.  
  1664.    for(n = 0; n < 1; n++)
  1665.       args[n] = 0;
  1666.  
  1667.    myrdargs = AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
  1668.    if (!myrdargs)
  1669.       {
  1670.       PrintFault(IoErr(), NULL);
  1671.       return FALSE;
  1672.       }
  1673.  
  1674.    myrdargs->RDA_ExtHelp = HelpTxt;
  1675.  
  1676.    if (!(rargs = (struct RDArgs *)ReadArgs(TEMPLATE, args, myrdargs)))
  1677.       {
  1678.       PrintFault(IoErr(), NULL);
  1679.       FreeDosObject(DOS_RDARGS, myrdargs);
  1680.       return FALSE;
  1681.       }
  1682.  
  1683.    if (args[0]) /* AREANAME */
  1684.       Areaname = (STRPTR)strdup((STRPTR)args[0]);
  1685.  
  1686.    FreeArgs(rargs);
  1687.    FreeDosObject(DOS_RDARGS, myrdargs);
  1688.  
  1689.    return TRUE;
  1690.    }
  1691.  
  1692. ///
  1693.  
  1694. /****************************
  1695.  * Sense                    *
  1696.  ****************************
  1697.  * I: ---                   *
  1698.  * O: ---                   *
  1699.  ****************************/
  1700.  
  1701. /// "Sense"
  1702.  
  1703. VOID Sense(APTR app, STRPTR str)
  1704.    {
  1705.    if (app)
  1706.       MUI_DisposeObject(app);
  1707.    if (Areaname)
  1708.       free(Areaname);
  1709.  
  1710.    if (KMSBase)
  1711.       {
  1712.       /* Von der Basis abmelden */
  1713.  
  1714.       ReleaseSemaphore(&KMSBase->BaseSem);
  1715.  
  1716.       /* KMSBase gegebenenfalls wieder entfernen */
  1717.  
  1718.       Forbid();
  1719.       if (KMSBase = (struct KMSBase *)FindSemaphore(KMSBASENAME))
  1720.          {
  1721.          if (AttemptSemaphore(&KMSBase->BaseSem))
  1722.             {
  1723.             Permit();
  1724.  
  1725.             /* Arealiste freigeben */
  1726.  
  1727.             struct AreaNode *apoint = KMSBase->AreaList.mlh_Head;
  1728.             while(apoint->Node.mln_Succ)
  1729.                {
  1730.                struct AreaNode *nextapoint = apoint->Node.mln_Succ;
  1731.                Remove((struct Node *)apoint);
  1732.                FreeMem(apoint, (ULONG)sizeof(struct AreaNode));
  1733.                apoint = nextapoint;
  1734.                }
  1735.  
  1736.             /* Userliste freigeben */
  1737.  
  1738.             struct UserNode *upoint = KMSBase->UserList.mlh_Head;
  1739.             while(upoint->Node.mln_Succ)
  1740.                {
  1741.                struct UserNode *nextupoint = upoint->Node.mln_Succ;
  1742.                Remove((struct Node *)upoint);
  1743.                FreeMem(upoint, (ULONG)sizeof(struct UserNode));
  1744.                upoint = nextupoint;
  1745.                }
  1746.  
  1747.             if (KMSBase->DatDir)
  1748.                FreeMem(KMSBase->DatDir, strlen(KMSBase->DatDir) + 1);
  1749.             if (KMSBase->UserDir)
  1750.                FreeMem(KMSBase->UserDir, strlen(KMSBase->UserDir) + 1);
  1751.  
  1752.             RemSemaphore(&KMSBase->BaseSem);
  1753.  
  1754.             ObtainSemaphore(&KMSBase->UserSem);
  1755.             ReleaseSemaphore(&KMSBase->UserSem);
  1756.             ObtainSemaphore(&KMSBase->AreaSem);
  1757.             ReleaseSemaphore(&KMSBase->AreaSem);
  1758.             ObtainSemaphore(&KMSBase->SaveSem);
  1759.             ReleaseSemaphore(&KMSBase->SaveSem);
  1760.  
  1761.             ReleaseSemaphore(&KMSBase->BaseSem);
  1762.  
  1763.             FreeMem(KMSBase->BaseSem.ss_Link.ln_Name, sizeof(KMSBASENAME)+1);
  1764.  
  1765.             FreeMem(KMSBase, sizeof(struct KMSBase));
  1766.             }
  1767.          else
  1768.             Permit();
  1769.          }
  1770.       else
  1771.          Permit();
  1772.       }
  1773.  
  1774.    /* Misc */
  1775.  
  1776.    if (UMSBase)
  1777.       {
  1778.       if (SysUMSAccount)
  1779.          UMSLogout(SysUMSAccount);
  1780.       CloseLibrary(UMSBase);
  1781.       }
  1782.  
  1783.    if (str)
  1784.       {
  1785.       fputs(str, stderr);
  1786.       fputs("\n", stderr);
  1787.       exit(20);
  1788.       }
  1789.  
  1790.    exit(0);
  1791.    }
  1792.  
  1793. ///
  1794.  
  1795. /****************************
  1796.  * AccessBits einlesen      *
  1797.  ****************************
  1798.  * I: ---                   *
  1799.  * O: ---                   *
  1800.  ****************************/
  1801.  
  1802. /// "ReadAccBits"
  1803.  
  1804. VOID ReadAccBits(VOID)
  1805.    {
  1806.    TEXT dos[LEN_DOSPATH+1];
  1807.    TEXT buff[LEN_NUMBER+LEN_ACCBITNAME+2];
  1808.    UWORD n;
  1809.    FILE *datei;
  1810.  
  1811.    strcpy(dos, KMSBase->DatDir);
  1812.    strcat(dos, "KMS_SYSTEM.DAT");
  1813.  
  1814.    ObtainSemaphore(&KMSBase->SaveSem);
  1815.  
  1816.    SystemStartups = 1;
  1817.    for(n = 0; n < 32; n++)
  1818.       sprintf(AccBitNames[n], "[Bit#%02d]", n+1);
  1819.  
  1820.    if (datei = fopen(dos, "r"))
  1821.       {
  1822.       fgets(buff, LEN_NUMBER+2, datei);
  1823.       SystemStartups = atol(buff) + 1;
  1824.  
  1825.       for(n = 0; n < 32; n++)
  1826.          {
  1827.          *buff = '\0';
  1828.          if (fgets(buff, LEN_ACCBITNAME+2, datei))
  1829.             buff[strlen(buff)-1] = '\0';
  1830.  
  1831.          if (!strlen(buff))
  1832.             sprintf(AccBitNames[n], "[Bit#%02d]", n+1);
  1833.          else
  1834.             strcpy(AccBitNames[n], buff);
  1835.          }
  1836.  
  1837.       fclose(datei);
  1838.       }
  1839.    }
  1840.  
  1841. ///
  1842.  
  1843. /***************************
  1844.  * AccessBits speichern    *
  1845.  ***************************
  1846.  * I: ---                  *
  1847.  * O: Erfolg TRUE/FALSE    *
  1848.  ***************************/
  1849.  
  1850. /// "WriteAccBits"
  1851.  
  1852. BOOL WriteAccBits(VOID)
  1853.    {
  1854.    FILE *datei;
  1855.    TEXT dos[LEN_DOSPATH+1];
  1856.    UBYTE n;
  1857.  
  1858.    /* Systemdaten werden nur im Besitz der Semaphore geschrieben! */
  1859.  
  1860.    ObtainSemaphore(&KMSBase->SaveSem);
  1861.  
  1862.    strcpy(dos, KMSBase->DatDir);
  1863.    strcat(dos, "KMS_SYSTEM.DAT");
  1864.  
  1865.    datei = fopen(dos, "w");
  1866.    if (datei)
  1867.       {
  1868.       fprintf(datei, "%ld\n", SystemStartups);
  1869.       for(n = 0; n < 32; n++)
  1870.          fprintf(datei, "%s\n", AccBitNames[n]);
  1871.  
  1872.       fclose(datei);
  1873.       }
  1874.  
  1875.    ReleaseSemaphore(&KMSBase->SaveSem);
  1876.  
  1877.    if (datei)
  1878.       return TRUE;
  1879.    else
  1880.       return FALSE;
  1881.    }
  1882.  
  1883. ///
  1884.  
  1885. /********************************
  1886.  * Area in Liste suchen         *
  1887.  ********************************
  1888.  * I: Area-Index                *
  1889.  * O: struct AreaNode *         *
  1890.  ********************************/
  1891.  
  1892. /// "SetArea"
  1893.  
  1894. struct AreaNode *SetArea(UWORD idx)
  1895.    {
  1896.    struct AreaNode *apoint;
  1897.  
  1898.    if (!idx)
  1899.       return NULL;
  1900.  
  1901.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1902.  
  1903.    if (apoint->Node.mln_Succ)
  1904.       {
  1905.       while (apoint->Node.mln_Succ && apoint->AreaData.ID != idx)
  1906.          apoint = (struct AreaNode *)apoint->Node.mln_Succ;
  1907.  
  1908.       if (apoint->Node.mln_Succ)
  1909.          return apoint;
  1910.       else
  1911.          return NULL;
  1912.       }
  1913.    else
  1914.       return NULL;
  1915.    }
  1916.  
  1917. ///
  1918.  
  1919. /*********************************
  1920.  * Start-Area suchen             *
  1921.  *********************************
  1922.  * I: STRPTR Pfad                *
  1923.  * O: struct AreaNode *          *
  1924.  *********************************/
  1925.  
  1926. /// "ResolvePath"
  1927.  
  1928. struct AreaNode *ResolvePath(STRPTR path)
  1929.    {
  1930.    struct AreaNode *current = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  1931.    BOOL begin = TRUE;
  1932.    TEXT token[LEN_AREANAME+1];
  1933.  
  1934.    if (!path || !strlen(path))
  1935.       return NULL;
  1936.  
  1937.    if (!current->Node.mln_Succ)
  1938.       return NULL;
  1939.  
  1940.    TakeASem(FALSE);
  1941.  
  1942.    if (strchr(path, '/'))
  1943.       {
  1944.       /* Angegebenen Pfad streng verfolgen */
  1945.       /* BRETT MAUS/AMIGA */
  1946.       /* BRETT /MAUS/AMIGA */
  1947.       /* BRETT / */
  1948.  
  1949.       do
  1950.          {
  1951.          path = PathParse(path, token);
  1952.  
  1953.          if (!strcmp(token, "/") && begin)
  1954.             {
  1955.             /* Wechsel ins Hauptverzeichnis (Private Mail) */
  1956.  
  1957.             CurrentMother = NULL;
  1958.             current = SetArea(1);
  1959.             }
  1960.  
  1961.          if (begin && *path)
  1962.             {
  1963.             /* Wechsel ins erste Unterverzeichnis */
  1964.  
  1965.             CurrentMother = current;
  1966.             current = SetArea(current->AreaData.Daughter);
  1967.             }
  1968.  
  1969.          if (!strcmp(token, "/"))
  1970.             {
  1971.             /* Wechsel ins Unterverzeichnis */
  1972.  
  1973.             if (!begin)
  1974.                {
  1975.                CurrentMother = current;
  1976.                current = SetArea(current->AreaData.Daughter);
  1977.                }
  1978.             }
  1979.          else
  1980.             {
  1981.             /* Brettname im aktuellen Verzeichnis suchen */
  1982.  
  1983.             while(current && stricmp(current->AreaData.Name, token))
  1984.                current = SetArea(current->AreaData.Next);
  1985.             }
  1986.  
  1987.          begin = FALSE;
  1988.  
  1989.          } while(*path && current);
  1990.  
  1991.       if (*path && !current)
  1992.          CurrentMother = NULL;
  1993.  
  1994.       DropASem();
  1995.  
  1996.       return current;
  1997.       }
  1998.    else
  1999.       {
  2000.       /* Einzelnes Brett global suchen */
  2001.  
  2002.       CurrentMother = NULL;
  2003.       current = SetArea(1);
  2004.  
  2005.       current = SeekAreaName(current, path);
  2006.       if (current)
  2007.          CurrentMother = SetArea(current->AreaData.Mother);
  2008.  
  2009.       DropASem();
  2010.  
  2011.       return current;
  2012.       }
  2013.    }
  2014.  
  2015. ///
  2016.  
  2017. /*********************************************
  2018.  * Nächsten Brettnamen aus Pfadangabe ziehen *
  2019.  *********************************************
  2020.  * I: Pfadstring, Tokenbuffer                *
  2021.  * O: Modifizierter Pfadstring               *
  2022.  *********************************************/
  2023.  
  2024. /// "PathParse"
  2025.  
  2026. STRPTR PathParse(STRPTR string, STRPTR tok)
  2027.    {
  2028.    UWORD n = 0;
  2029.  
  2030.    *tok = '\0';
  2031.  
  2032.    if (*string == '/')
  2033.       {
  2034.       tok[0] = *string;
  2035.       tok[1] = '\0';
  2036.       return ++string;
  2037.       }
  2038.  
  2039.    while(*string && *string != '/')
  2040.       {
  2041.       tok[n++] = *string;
  2042.       string++;
  2043.       }
  2044.  
  2045.    tok[n] = '\0';
  2046.  
  2047.    return string;
  2048.    }
  2049.  
  2050. ///
  2051.  
  2052. /*******************************************
  2053.  * Area mit bestimmtem Namen global suchen *
  2054.  *******************************************
  2055.  * I: Start-Area, Name                     *
  2056.  * O: Gefundene Area oder NULL             *
  2057.  *******************************************/
  2058.  
  2059. /// "SeekAreaName"
  2060.  
  2061. struct AreaNode *SeekAreaName(struct AreaNode *current, STRPTR name)
  2062.    {
  2063.    BOOL goon = TRUE;
  2064.    BOOL stop = FALSE;
  2065.  
  2066.    TakeASem(FALSE);
  2067.  
  2068.    while(current && goon)
  2069.       {
  2070.       if (current->AreaData.Daughter && !stop)
  2071.          {
  2072.          current = SetArea(current->AreaData.Daughter);
  2073.          stop = FALSE;
  2074.          }
  2075.       else if (current->AreaData.Next)
  2076.          {
  2077.          current = SetArea(current->AreaData.Next);
  2078.          stop = FALSE;
  2079.          }
  2080.       else
  2081.          {
  2082.          current = SetArea(current->AreaData.Mother);
  2083.          stop = TRUE;
  2084.          }
  2085.  
  2086.       if (current && (!stop || !current->AreaData.Mother) && !stricmp(current->AreaData.Name, name))
  2087.          goon = FALSE;
  2088.       }
  2089.  
  2090.    DropASem();
  2091.  
  2092.    return current;
  2093.    }
  2094.  
  2095. ///
  2096.  
  2097. /*******************************************
  2098.  * UMS-MsgBase-Namen global suchen         *
  2099.  *******************************************
  2100.  * I: gesuchte Area                        *
  2101.  * O: AreaNode                             *
  2102.  *******************************************/
  2103.  
  2104. /// "AreaSearch"
  2105.  
  2106. struct AreaNode *AreaSearch(STRPTR name)
  2107.    {
  2108.    struct AreaNode *apoint;
  2109.  
  2110.    TakeASem(FALSE);
  2111.  
  2112.    apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  2113.    while(apoint->Node.mln_Succ)
  2114.       {
  2115.       if (!stricmp(name, apoint->AreaData.MBName))
  2116.          {
  2117.          DropASem();
  2118.          return apoint;
  2119.          }
  2120.  
  2121.       apoint = apoint->Node.mln_Succ;
  2122.       }
  2123.  
  2124.    DropASem();
  2125.  
  2126.    return NULL;
  2127.    }
  2128.  
  2129. ///
  2130.  
  2131. /********************************
  2132.  * Neue Area einhängen          *
  2133.  ********************************
  2134.  * I: struct AreaNode *         *
  2135.  * O: LONG                      *
  2136.  ********************************/
  2137.  
  2138. /// "InsertArea"
  2139.  
  2140. LONG InsertArea(struct AreaNode *newan)
  2141.    {
  2142.    LONG index = 0;
  2143.  
  2144.    if (!CurrentMother->AreaData.Daughter)
  2145.       {
  2146.       /* Neue erste Tochter */
  2147.  
  2148.       CurrentMother->AreaData.Daughter = newan->AreaData.ID;
  2149.  
  2150.       newan->AreaData.Mother = CurrentMother->AreaData.ID;
  2151.       newan->AreaData.Next = 0;
  2152.  
  2153.       CurrentArea = newan;
  2154.  
  2155.       return 0;
  2156.       }
  2157.    else
  2158.       {
  2159.       /* Weitere Tochter einsortieren */
  2160.  
  2161.       struct AreaNode *daughter, *predaughter;
  2162.       daughter = SetArea(CurrentMother->AreaData.Daughter);
  2163.       predaughter = NULL;
  2164.  
  2165.       if (CurrentArea)
  2166.          {
  2167.          /* Nach der aktuellen Area einsortieren */
  2168.  
  2169.          while(daughter && daughter != CurrentArea)
  2170.             {
  2171.             index++;
  2172.  
  2173.             predaughter = daughter;
  2174.             if (daughter->AreaData.Next)
  2175.                daughter = SetArea(daughter->AreaData.Next);
  2176.             else
  2177.                daughter = NULL;
  2178.             }
  2179.          }
  2180.       else
  2181.          {
  2182.          /* Alphabetisch einsortieren */
  2183.  
  2184.          while(daughter && stricmp(newan->AreaData.Name, daughter->AreaData.Name) != -1)
  2185.             {
  2186.             index++;
  2187.  
  2188.             predaughter = daughter;
  2189.             if (daughter->AreaData.Next)
  2190.                daughter = SetArea(daughter->AreaData.Next);
  2191.             else
  2192.                daughter = NULL;
  2193.             }
  2194.          }
  2195.  
  2196.       newan->AreaData.Mother = CurrentMother->AreaData.ID;
  2197.  
  2198.       if (!predaughter)
  2199.          {
  2200.          /* Neue Area ist die erste */
  2201.  
  2202.          newan->AreaData.Next = daughter->AreaData.ID;
  2203.          CurrentMother->AreaData.Daughter = newan->AreaData.ID;
  2204.          }
  2205.       else if (!daughter)
  2206.          {
  2207.          /* Neue Area ist die letzte */
  2208.  
  2209.          predaughter->AreaData.Next = newan->AreaData.ID;
  2210.          newan->AreaData.Next = 0;
  2211.          }
  2212.       else
  2213.          {
  2214.          /* Neue Area zwischen predaughter und daughter einhängen */
  2215.  
  2216.          predaughter->AreaData.Next = newan->AreaData.ID;
  2217.          newan->AreaData.Next = daughter->AreaData.ID;
  2218.          }
  2219.  
  2220.       CurrentArea = newan;
  2221.  
  2222.       return index;
  2223.       }
  2224.    }
  2225.  
  2226. ///
  2227.  
  2228. /********************************
  2229.  * Area aus Arealiste entfernen *
  2230.  ********************************
  2231.  * I: struct AreaNode *         *
  2232.  * O: ---                       *
  2233.  ********************************/
  2234.  
  2235. /// "RemoveArea"
  2236.  
  2237. VOID RemoveArea(struct AreaNode *delan)
  2238.    {
  2239.    /* Wenn zu löschendes Brett erstes Tochterbrett ist, */
  2240.    /* dann Mutter auf nächste Tochter einstimmen ;-)    */
  2241.  
  2242.    if (delan->AreaData.ID == CurrentMother->AreaData.Daughter)
  2243.       {
  2244.       if (delan->AreaData.Next)
  2245.          CurrentMother->AreaData.Daughter = delan->AreaData.Next;
  2246.       else
  2247.          CurrentMother->AreaData.Daughter = 0;
  2248.       }
  2249.  
  2250.    /* Wenn zu löschendes Brett nicht einziges Unterbrett, */
  2251.    /* dann "Next"-Zeiger aktualisieren                    */
  2252.  
  2253.    if (CurrentMother->AreaData.Daughter)
  2254.       {
  2255.       struct AreaNode *tempan = NULL;
  2256.       struct AreaNode *prean = NULL;
  2257.  
  2258.       tempan = SetArea(CurrentMother->AreaData.Daughter);
  2259.  
  2260.       while(tempan && tempan != delan)
  2261.          {
  2262.          prean = tempan;
  2263.  
  2264.          if (tempan->AreaData.Next)
  2265.             tempan = SetArea(tempan->AreaData.Next);
  2266.          else
  2267.             tempan = NULL;
  2268.          }
  2269.  
  2270.       if (prean && tempan == delan)
  2271.          prean->AreaData.Next = delan->AreaData.Next;
  2272.       }
  2273.    }
  2274.  
  2275. ///
  2276.  
  2277. /********************************
  2278.  * Areas ohne Mutter löschen    *
  2279.  ********************************
  2280.  * I: ---                       *
  2281.  * O: ---                       *
  2282.  ********************************/
  2283.  
  2284. /// CleanUpAreaList
  2285.  
  2286. VOID CleanUpAreaList(VOID)
  2287.    {
  2288.    CurrentArea = NULL;
  2289.    struct AreaNode *apoint, *next;
  2290.    UWORD loops = 1;
  2291.  
  2292.    while(loops)
  2293.       {
  2294.       apoint = (struct AreaNode *)KMSBase->AreaList.mlh_Head;
  2295.       while(apoint->Node.mln_Succ)
  2296.          {
  2297.          next = apoint->Node.mln_Succ;
  2298.  
  2299.          if (!SetArea(apoint->AreaData.Mother) && apoint->AreaData.ID != 1)
  2300.             {
  2301.             /* Area ist Waise, also löschen */
  2302.  
  2303.             if (apoint->AreaData.Daughter != 0)
  2304.                /* Brett hat selber Unterbretter, also muessen wir einen
  2305.                   weiteren Durchlauf machen */
  2306.                loops++;
  2307.  
  2308.             DeleteAN(apoint);
  2309.             }
  2310.  
  2311.          apoint = next;
  2312.          }
  2313.  
  2314.       loops--;
  2315.       }
  2316.    }
  2317.  
  2318. ///
  2319.  
  2320. /********************************
  2321.  * KMSBase besorgen             *
  2322.  ********************************
  2323.  * I: ---                       *
  2324.  * O: struct KMSBase *          *
  2325.  ********************************/
  2326.  
  2327. /// "GetKMSBase"
  2328.  
  2329. struct KMSBase *GetKMSBase(VOID)
  2330.    {
  2331.    STRPTR bname;
  2332.  
  2333.    /* KMSBase erzeugen, falls nicht vorhanden */
  2334.  
  2335.    Forbid();
  2336.  
  2337.    if (!(KMSBase = (struct KMSBase *)FindSemaphore(KMSBASENAME)))
  2338.       {
  2339.       bname = AllocMem((ULONG)sizeof(KMSBASENAME)+1, MEMF_PUBLIC|MEMF_CLEAR);
  2340.       if (bname)
  2341.          {
  2342.          strcpy(bname, KMSBASENAME);
  2343.  
  2344.          if (KMSBase = AllocMem((ULONG)sizeof(struct KMSBase), MEMF_PUBLIC|MEMF_CLEAR))
  2345.             {
  2346.             KMSBase->BaseSem.ss_Link.ln_Pri = 0;
  2347.             KMSBase->BaseSem.ss_Link.ln_Name = bname;
  2348.             KMSBase->UserSem.ss_Link.ln_Pri = 0;
  2349.             KMSBase->UserSem.ss_Link.ln_Name = NULL;
  2350.             KMSBase->AreaSem.ss_Link.ln_Pri = 0;
  2351.             KMSBase->AreaSem.ss_Link.ln_Name = NULL;
  2352.             KMSBase->SaveSem.ss_Link.ln_Pri = 0;
  2353.             KMSBase->SaveSem.ss_Link.ln_Name = NULL;
  2354.  
  2355.             NewList((struct List *)&KMSBase->AreaList);
  2356.             NewList((struct List *)&KMSBase->UserList);
  2357.  
  2358.             AddSemaphore(&KMSBase->BaseSem);
  2359.             InitSemaphore(&KMSBase->UserSem);
  2360.             InitSemaphore(&KMSBase->AreaSem);
  2361.             InitSemaphore(&KMSBase->SaveSem);
  2362.  
  2363.             ObtainSemaphore(&KMSBase->BaseSem);
  2364.  
  2365.             Permit();
  2366.  
  2367.             UMSBase = (struct Library *)OpenLibrary(UMSNAME, 0);
  2368.             if (!UMSBase)
  2369.                {
  2370.                Error("couldn't open ums.library.");
  2371.                return NULL;
  2372.                }
  2373.  
  2374.             TEXT varbuff[32] = "";
  2375.             TEXT pwbuff[32] = "";
  2376.             GetVar("KMSMB", varbuff, sizeof(varbuff), NULL);
  2377.             GetVar("KMSPWD", pwbuff, sizeof(pwbuff), NULL);
  2378.             if (!(SysUMSAccount = UMSRLogin(varbuff, "KMS", pwbuff)))
  2379.                {
  2380.                Error("couldn't log into UMS.");
  2381.                return NULL;
  2382.                }
  2383.  
  2384.             STRPTR string;
  2385.             if (string = ReadUMSConfigTags(SysUMSAccount, UMSTAG_CfgName, "KMS.datdir", TAG_DONE))
  2386.                {
  2387.                KMSBase->DatDir = AllocMem((ULONG)(strlen(string)+1), MEMF_PUBLIC|MEMF_CLEAR);
  2388.                if (KMSBase->DatDir)
  2389.                   strcpy(KMSBase->DatDir, string);
  2390.  
  2391.                FreeUMSConfig(SysUMSAccount, string);
  2392.  
  2393.                if (!KMSBase->DatDir)
  2394.                   {
  2395.                   Error("out of memory.");
  2396.                   return NULL;
  2397.                   }
  2398.                }
  2399.             else
  2400.                {
  2401.                KMSBase->DatDir = AllocMem((ULONG)(strlen("Data/")+1), MEMF_PUBLIC|MEMF_CLEAR);
  2402.                if (KMSBase->DatDir)
  2403.                   strcpy(KMSBase->DatDir, "Data/");
  2404.                else
  2405.                   {
  2406.                   Error("out of memory.");
  2407.                   return NULL;
  2408.                   }
  2409.                }
  2410.  
  2411.             if (string = ReadUMSConfigTags(SysUMSAccount, UMSTAG_CfgName, "KMS.userdir", TAG_DONE))
  2412.                {
  2413.                KMSBase->UserDir = AllocMem((ULONG)(strlen(string)+1), MEMF_PUBLIC|MEMF_CLEAR);
  2414.                if (KMSBase->UserDir)
  2415.                   strcpy(KMSBase->UserDir, string);
  2416.  
  2417.                FreeUMSConfig(SysUMSAccount, string);
  2418.  
  2419.                if (!KMSBase->UserDir)
  2420.                   {
  2421.                   Error("out of memory.");
  2422.                   return NULL;
  2423.                   }
  2424.                }
  2425.             else
  2426.                {
  2427.                KMSBase->UserDir = AllocMem((ULONG)(strlen("User/")+1), MEMF_PUBLIC|MEMF_CLEAR);
  2428.                if (KMSBase->UserDir)
  2429.                   strcpy(KMSBase->UserDir, "User/");
  2430.                else
  2431.                   {
  2432.                   Error("out of memory.");
  2433.                   return NULL;
  2434.                   }
  2435.                }
  2436.  
  2437.             ReleaseSemaphore(&KMSBase->BaseSem);
  2438.             ObtainSemaphoreShared(&KMSBase->BaseSem);
  2439.             }
  2440.          else
  2441.             {
  2442.             Permit();
  2443.  
  2444.             if (bname)
  2445.                FreeMem(bname, sizeof(KMSBASENAME)+1);
  2446.  
  2447.             Error("out of memory.");
  2448.  
  2449.             return NULL;
  2450.             }
  2451.          }
  2452.       else
  2453.          {
  2454.          Permit();
  2455.  
  2456.          Error("out of memory.");
  2457.  
  2458.          return NULL;
  2459.          }
  2460.       }
  2461.    else
  2462.       {
  2463.       Permit();
  2464.  
  2465.       ObtainSemaphoreShared(&KMSBase->BaseSem);
  2466.       }
  2467.  
  2468.    /* Arealiste einlesen oder anlegen, falls nicht vorhanden */
  2469.  
  2470.    if (!ReadAreaList())
  2471.       {
  2472.       InitAreaFile();
  2473.       if (!ReadAreaList())
  2474.          {
  2475.          Error("couldn't create or read area file.");
  2476.          return NULL;
  2477.          }
  2478.       }
  2479.  
  2480.    ReadAccBits();
  2481.  
  2482.    return KMSBase;
  2483.    }
  2484.  
  2485. ///
  2486.  
  2487. /***************************************
  2488.  *  Pfad-String konstruieren           *
  2489.  ***************************************
  2490.  * I: STRPTR                           *
  2491.  * O: ---                              *
  2492.  ***************************************/
  2493.  
  2494. /// "CreatePath"
  2495.  
  2496. VOID CreatePath(STRPTR path)
  2497.    {
  2498.    struct AreaNode *apoint;
  2499.    TEXT merk[LEN_KMSPATH+1];
  2500.  
  2501.    apoint = CurrentArea;
  2502.    if (!apoint)
  2503.       {
  2504.       apoint = CurrentMother;
  2505.       if (!apoint)
  2506.          {
  2507.          *path = '\0';
  2508.          return;
  2509.          }
  2510.       }
  2511.  
  2512.    strcpy(path, apoint->AreaData.Name);
  2513.  
  2514.    if (!CurrentArea)
  2515.       strcat(path, "/");
  2516.  
  2517.    while(apoint && apoint->AreaData.Mother && strlen(path) < LEN_KMSPATH)
  2518.       {
  2519.       apoint = SetArea(apoint->AreaData.Mother);
  2520.       strcpy(merk, path);
  2521.       if (apoint && apoint->AreaData.ID != 1)
  2522.          strcpy(path, apoint->AreaData.Name);
  2523.       else
  2524.          *path = '\0';
  2525.       strcat(path, "/");
  2526.       strncat(path, merk, LEN_KMSPATH - strlen(merk));
  2527.       path[LEN_KMSPATH] = '\0';
  2528.       }
  2529.    }
  2530.  
  2531. ///
  2532.  
  2533. /***************************************
  2534.  *  Pfad-String aktualisieren          *
  2535.  ***************************************
  2536.  * I: ---                              *
  2537.  * O: ---                              *
  2538.  ***************************************/
  2539.  
  2540. /// "UpdatePath"
  2541.  
  2542. VOID UpdatePath(VOID)
  2543.    {
  2544.    CreatePath(PathString);
  2545.  
  2546.    /*
  2547.    set(ST_Path, MUIA_String_Contents, PathString);
  2548.    */
  2549.    set(ST_Path, MUIA_Text_Contents, PathString);
  2550.    }
  2551.  
  2552. ///
  2553.  
  2554. /********************************
  2555.  * String -> Großbuchstaben     *
  2556.  ********************************
  2557.  * I: STRPTR                    *
  2558.  * O: ---                       *
  2559.  ********************************/
  2560.  
  2561. /// "Upper"
  2562.  
  2563. VOID Upper(STRPTR string)
  2564.    {
  2565.    if (!string)
  2566.       return;
  2567.  
  2568.    while(*string)
  2569.       {
  2570.       switch((UBYTE)*string)
  2571.          {
  2572.          case 'ä':
  2573.             *string = 'Ä';
  2574.             break;
  2575.          case 'ö':
  2576.             *string = 'Ö';
  2577.             break;
  2578.          case 'ü':
  2579.             *string = 'Ü';
  2580.             break;
  2581.          default:
  2582.             *string = toupper(*string);
  2583.          }
  2584.  
  2585.       string++;
  2586.       }
  2587.    }
  2588.  
  2589. ///
  2590.  
  2591. /********************************
  2592.  * Standardfehlerausgabe        *
  2593.  ********************************
  2594.  * I: ---                       *
  2595.  * O: ---                       *
  2596.  ********************************/
  2597.  
  2598. /// "Error"
  2599.  
  2600. VOID Error(STRPTR errtxt)
  2601.    {
  2602.    if (errtxt)
  2603.       {
  2604.       fputs(errtxt, stderr);
  2605.       fputs("\n", stderr);
  2606.       }
  2607.    }
  2608.  
  2609. ///
  2610.  
  2611. /// "TakeASem"
  2612.  
  2613. VOID TakeASem(BOOL exclusive)
  2614.    {
  2615.    if (exclusive)
  2616.       ObtainSemaphore(&KMSBase->AreaSem);
  2617.    else
  2618.       ObtainSemaphoreShared(&KMSBase->AreaSem);
  2619.    }
  2620.  
  2621. ///
  2622.  
  2623. /// "DropASem"
  2624.  
  2625. VOID DropASem(VOID)
  2626.    {
  2627.    ReleaseSemaphore(&KMSBase->AreaSem);
  2628.    }
  2629.  
  2630. ///
  2631.  
  2632. /// "TakeMSem"
  2633.  
  2634. VOID TakeMSem(BOOL exclusive)
  2635.    {
  2636.    if (exclusive)
  2637.       ObtainSemaphore(&KMSBase->SaveSem);
  2638.    else
  2639.       ObtainSemaphoreShared(&KMSBase->SaveSem);
  2640.    }
  2641.  
  2642. ///
  2643.  
  2644. /// "DropMSem"
  2645.  
  2646. VOID DropMSem(VOID)
  2647.    {
  2648.    ReleaseSemaphore(&KMSBase->SaveSem);
  2649.    }
  2650.  
  2651. ///
  2652.